<template>
    <div class="add-role">
        <el-dialog v-model="dialogVisible" class="review-dialog role-dialog" width="615" :show-close="false"
            :close-on-click-modal="false" :close-on-press-escape="false">
            <div class="header">
                <div class="title">{{ id ? '更新' : '新增' }}角色</div>
                <div class="header-right">
                    <div class="close" @click="close">
                        <i class="iconfont icon-chahao1 close-dialog"></i>
                    </div>
                </div>
            </div>
            <div class="content">
                <div class="content-top">
                    <div class="role">
                        <div class="role-name">角色名称：</div>
                        <el-input placeholder="请输入角色名称" v-model="roleName" style="width: 150px;"></el-input>
                    </div>
                    <div class="role">
                        <div class="role-name">关键词：</div>
                        <el-input placeholder="请输入角色关键词，并确保其唯一" v-model="unKey" style="width: 250px;"></el-input>
                    </div>
                </div>
                <div class="tree-type">
                    <el-radio-group v-model="treeType" @change="typeChange">
                        <el-radio-button label="前台权限" value="font" />
                        <el-radio-button label="接口权限" value="backend" />
                    </el-radio-group>
                </div>
                <div class="tree" v-loading="permissionLoading">
                    <el-tree ref="roleTree" :data="treeType == '前台权限' ? fontRoleList : backendRoleList" node-key="id"
                        default-expand-all :props="props" show-checkbox @check-change="checkChange"
                        :check-strictly="true" @check="handleCheck" />
                </div>
            </div>
            <div class="footer">
                <div class="btn primary" @click="confirm">确 定</div>
                <div class="btn default" @click="close">取 消</div>
            </div>
        </el-dialog>
    </div>
</template>

<script setup>
import { ref, onMounted, watch, computed, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router";
import { getAllPermissionAPI, addRoleAPI, updateRoleAPI } from '@/api/adminAPI/adminAPI'
import { ElMessage } from "element-plus";

const emit = defineEmits(['regetRoleList'])

const dialogVisible = ref(false);

const roleName = ref('')
const permissionLoading = ref(true)
const permissionList = ref([])
const roleTree = ref(null)
const unKey = ref('')
const id = ref(null)
const debounce = ref(null)
const fontRoleList = ref([])
const backendRoleList = ref([])
const fontChoisePermission = ref([])
const backendChoisePermission = ref([])
const treeType = ref('前台权限')

const choisePermission = computed(() => {
    return [...fontChoisePermission.value, ...backendChoisePermission.value]
})

const open = (data = null) => {
    dialogVisible.value = true
    if (!permissionList.value.length) {
        getAllPermission()
    }
    if (data) {
        id.value = data.id
        roleName.value = data.name
        unKey.value = data.unKey
        if (data?.permissionVOList?.length) {
            fontChoisePermission.value = data.permissionVOList.filter(item => item.type == 1).map(item => item.id)
            backendChoisePermission.value = data.permissionVOList.filter(item => item.type == 0).map(item => item.id)
        }
        nextTick(() => {
            roleTree.value.setCheckedKeys(fontChoisePermission.value)
        })
    }
}

const close = () => {
    dialogVisible.value = false
    roleTree.value.setCheckedKeys([]);
    fontChoisePermission.value = []
    backendChoisePermission.value = []
    id.value = null
    treeType.value = '前台权限'
}
const props = {
    value: 'id',
    label: 'name',
    children: 'children'
}

const checkChange = () => {
    if (treeType.value == '前台权限') {
        fontChoisePermission.value = roleTree.value.getCheckedKeys()
    } else {
        backendChoisePermission.value = roleTree.value.getCheckedKeys()
    }
}
const typeChange = () => {
    nextTick(() => {
        if (treeType.value == '前台权限') {
            roleTree.value.setCheckedKeys(fontChoisePermission.value);
        } else {
            roleTree.value.setCheckedKeys(backendChoisePermission.value);
        }
    })
}

const confirm = () => {
    if (debounce.value) {
        clearTimeout(debounce.value)
        debounce.value = null
    }
    debounce.value = setTimeout(() => {
        if (!roleName.value) {
            ElMessage.error('请填写角色名称')
            return
        }
        if (!unKey.value) {
            ElMessage.error('请填写角色关键词')
            return
        }
        if (!choisePermission.value.length) {
            ElMessage.error('请选择至少一个权限')
            return
        }
        if (id.value) {
            updateRole()
        } else {
            addRole()
        }
    }, 300)
}

const buildPermissionTree = (permissions) => {
    // 1. 创建 id 到节点的映射（初始化 children 数组）
    const nodeMap = new Map();
    permissions.forEach(perm => {
        nodeMap.set(perm.id, { ...perm, children: [] });
    });

    // 2. 建立父子关系（related 指向父节点）
    permissions.forEach(perm => {
        try {
            const parentIds = JSON.parse(perm.related.replace(/'/g, '"'))
                .map(id => String(id));

            parentIds.forEach(parentId => {
                if (nodeMap.has(parentId)) {
                    // 将当前节点添加到父节点的 children 中
                    nodeMap.get(parentId).children.push(nodeMap.get(perm.id));
                }
            });
        } catch (e) {
            // 忽略解析错误
        }
    });

    // 3. 找出所有根节点（没有父节点的节点）
    const rootNodes = [];
    const hasParent = new Set();

    permissions.forEach(perm => {
        try {
            const parentIds = JSON.parse(perm.related.replace(/'/g, '"'))
                .map(id => String(id));

            parentIds.forEach(parentId => {
                if (nodeMap.has(parentId)) {
                    hasParent.add(perm.id);
                }
            });
        } catch (e) {
            // 没有父节点的节点也可能是根节点
        }
    });

    // 4. 收集所有未被任何节点引用的节点（即 related 为空的节点）
    permissions.forEach(perm => {
        if (!hasParent.has(perm.id) && perm.related === "[]") {
            rootNodes.push(nodeMap.get(perm.id));
        }
    });

    return rootNodes;
}

const handleCheck = (checkedNode, checkedNodes) => {
    // 使用 nextTick 确保 DOM 更新完成
    nextTick(() => {
        updateParentChecked(checkedNode);
    });
};

const updateParentChecked = (node) => {
    const treeInstance = roleTree.value;

    if (!treeInstance) return;

    const nodeInstance = treeInstance.getNode(node);
    if (!nodeInstance || !nodeInstance.parent || nodeInstance.parent.level === 0) return;

    // 检查所有兄弟节点是否都被选中
    const allChildrenChecked = nodeInstance.parent.childNodes.every(
        child => child.checked === true
    );


    // 设置父节点选中状态，不触发事件
    treeInstance.setChecked(nodeInstance.parent.data, allChildrenChecked, false);

    // 递归向上检查
    updateParentChecked(nodeInstance.parent.data);
};

const getAllPermission = async () => {
    permissionLoading.value = true
    try {
        const response = await getAllPermissionAPI()
        const { code, data, msg } = response.data
        if (code == 200) {
            permissionList.value = buildPermissionTree(data)
            fontRoleList.value = permissionList.value.filter(item => item.type == 1)
            backendRoleList.value = permissionList.value.filter(item => item.type == 0)
        }
    } catch (err) {
        console.log(err)
    } finally {
        setTimeout(() => {
            permissionLoading.value = false
        }, 300)
    }
}


const addRole = async () => {
    const postData = {
        name: roleName.value,
        unKey: unKey.value,
        permissions: JSON.stringify(choisePermission.value)
    }
    try {
        const response = await addRoleAPI(postData)
        const { code, data, message } = response.data
        if (code == 200) {
            ElMessage.success('添加成功')
            close()
            emit('regetRoleList')
        }
    } catch (err) {
        console.log(err)
    }
}

const updateRole = async () => {
    const postData = {
        name: roleName.value,
        unKey: unKey.value,
        permissions: JSON.stringify(choisePermission.value),
        id: id.value
    }
    try {
        const response = await updateRoleAPI(postData)
        const { code, data, message } = response.data
        if (code == 200) {
            ElMessage.success('修改成功')
            close()
            emit('regetRoleList')
        }
    } catch (err) {
        console.log(err)
    }
}

defineExpose({
    open
})

</script>

<style lang="less" scoped>
.add-role {
    .header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        margin-bottom: 10px;

        .title {
            line-height: 33px;
            font-weight: 700;
            font-size: 24px;
            color: #222;
        }

        .header-right {
            display: flex;
            align-items: center;
            justify-content: center;
            margin-top: 4px;

            .close {
                margin-left: 10px;

                .close-dialog {
                    cursor: pointer;
                    font-size: 34px;
                    color: #8c8c8c;
                    transition: all 0.3s ease-in-out;

                    &:hover {
                        color: #8c8c8cbd;
                    }
                }
            }
        }

    }

    .content {
        .content-top {
            display: flex;
            flex-wrap: nowrap;
            gap: 10px;
        }

        .tree-type {
            margin-top: 20px;
        }

        .role {
            display: flex;
            align-items: center;
            justify-content: left;
        }

        .tree {
            height: 350px;
            overflow: auto;
            margin-top: 10px;
        }
    }

    .footer {
        display: flex;
        justify-content: center;
        align-items: center;
        flex-wrap: nowrap;
        gap: 10px;
        padding: 5px;

        .btn {
            width: 100px;
            height: 40px;
            line-height: 40px;
            text-align: center;
            border-radius: 4px;
            cursor: pointer;
            transition: all 0.3s ease-in-out;

            &.primary {
                background-color: #409eff;
                color: #fff;

                &:hover {
                    background-color: #66b1ff;
                }
            }

            &.default {
                background-color: #cfcfcf;
                color: #fff;

                &:hover {
                    background-color: rgba(#cfcfcf, 0.8);
                }
            }

        }
    }
}

::v-deep(.el-input__wrapper) {
    transition: all 0.3s ease-in-out;

    &.is-focus {
        box-shadow: 0px 0px 0px 1px #c1c1c1 !important;
    }
}
</style>